package service

import (
	v1 "blog/api/v1"
	"blog/internal/model"
	"blog/internal/repository"
	"context"
	"errors"
	"gorm.io/gorm"
)

type ArticleService interface {
	CreateArticle(ctx context.Context, title string, content string, authorId uint, tagIDs []uint) error
	GetArticleByID(ctx context.Context, articleID uint) (*v1.ArticleResponse, error)
	ListArticles(ctx context.Context) ([]*v1.ArticleResponse, error)
	ListArticlesByAuthorID(ctx context.Context, authorID uint) ([]*v1.ArticleResponse, error)
	ListArticlesByTagID(ctx context.Context, tagID uint) ([]*v1.ArticleResponse, error)
	SearchArticlesByTitle(ctx context.Context, keyword string) ([]*v1.ArticleResponse, error)
	UpdateArticle(ctx context.Context, id uint, title string, content string, tagIDs []uint, userId uint, usertype uint) error
	DeleteArticleByArticleID(ctx context.Context, articleID uint, userId uint, usertype uint) error
}

func NewArticleService(
	service *Service,
	articleRepository repository.ArticleRepository,
	userRepo repository.UserRepository,
	relationSvc ArticleTagRelationService,
	tagSvc TagService,
	userSvc UserService,
) ArticleService {
	return &articleService{
		Service:     service,
		articleRepo: articleRepository,
		userRepo:    userRepo,
		relationSvc: relationSvc,
		tagSvc:      tagSvc,
		userSvc:     userSvc,
	}
}

type articleService struct {
	*Service
	articleRepo repository.ArticleRepository
	userRepo    repository.UserRepository
	relationSvc ArticleTagRelationService
	tagSvc      TagService
	userSvc     UserService
}

// 公共封装方法：构建 ArticleResponse 列表
func (s *articleService) buildArticleResponseList(ctx context.Context, articles []*model.Article) ([]*v1.ArticleResponse, error) {
	var result []*v1.ArticleResponse

	for _, article := range articles {
		tagIDs, err := s.relationSvc.GetTagIDsByArticleID(ctx, article.ID)
		if err != nil {
			return nil, err
		}

		tags, err := s.tagSvc.GetTagsByIDs(ctx, tagIDs)
		if err != nil {
			return nil, err
		}

		var tagResponses []v1.TagResponse
		for _, tag := range tags {
			tagResponses = append(tagResponses, v1.TagResponse{
				ID:   tag.ID,
				Name: tag.Name,
			})
		}

		user, err := s.userRepo.GetByID(ctx, article.AuthorID)
		if err != nil {
			if !errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, err
			}
			user = &model.User{
				UserName: "用户已注销",
			}
		}

		result = append(result, &v1.ArticleResponse{
			ID:        article.ID,
			AuthorID:  article.AuthorID,
			Author:    user.UserName,
			Title:     article.Title,
			Content:   article.Content,
			Tags:      tagResponses,
			CreatedAt: article.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return result, nil
}

func (s *articleService) CreateArticle(ctx context.Context, title string, content string, authorId uint, tagIDs []uint) error {
	article := &model.Article{
		Title:    title,
		Content:  content,
		AuthorID: authorId,
	}
	if err := s.articleRepo.CreateArticle(ctx, article); err != nil {
		return err
	}
	return s.relationSvc.CreateRelations(ctx, article.ID, tagIDs)
}

func (s *articleService) ListArticles(ctx context.Context) ([]*v1.ArticleResponse, error) {
	articles, err := s.articleRepo.ListArticle(ctx)
	if err != nil {
		return nil, err
	}
	return s.buildArticleResponseList(ctx, articles)
}
func (s *articleService) GetArticleByID(ctx context.Context, articleID uint) (*v1.ArticleResponse, error) {
	article, err := s.articleRepo.GetArticleByID(ctx, articleID)
	if err != nil {
		return nil, err
	}

	// 构建返回结果
	list, err := s.buildArticleResponseList(ctx, []*model.Article{article})
	if err != nil {
		return nil, err
	}

	if len(list) == 0 {
		return nil, errors.New("构建文章响应失败")
	}

	return list[0], nil
}

func (s *articleService) ListArticlesByAuthorID(ctx context.Context, authorID uint) ([]*v1.ArticleResponse, error) {

	articles, err := s.articleRepo.ListArticlesByAuthorID(ctx, authorID)
	if err != nil {
		return nil, err
	}

	return s.buildArticleResponseList(ctx, articles)
}

func (s *articleService) ListArticlesByTagID(ctx context.Context, tagID uint) ([]*v1.ArticleResponse, error) {
	articleIDs, err := s.relationSvc.GetArticleIDsByTagID(ctx, tagID)
	if err != nil {
		return nil, err
	}

	var articles []*model.Article
	for _, id := range articleIDs {
		article, err := s.articleRepo.GetArticleByID(ctx, id)
		if err != nil || article == nil {
			continue
		}
		articles = append(articles, article)
	}

	return s.buildArticleResponseList(ctx, articles)
}

func (s *articleService) SearchArticlesByTitle(ctx context.Context, keyword string) ([]*v1.ArticleResponse, error) {
	articles, err := s.articleRepo.SearchArticlesByTitle(ctx, keyword)
	if err != nil {
		return nil, err
	}
	return s.buildArticleResponseList(ctx, articles)
}

func (s *articleService) UpdateArticle(ctx context.Context, id uint, title string, content string, tagIDs []uint, userId uint, usertype uint) error {
	if err := s.isPermission(ctx, id, userId, usertype); err != nil {
		return err
	}

	article := &model.Article{
		ID:       id,
		Title:    title,
		AuthorID: userId,
		Content:  content,
	}

	if err := s.articleRepo.UpdateArticle(ctx, article); err != nil {
		return err
	}
	if err := s.relationSvc.DeleteRelationsByArticleID(ctx, id); err != nil {
		return err
	}
	return s.relationSvc.CreateRelations(ctx, id, tagIDs)
}

func (s *articleService) DeleteArticleByArticleID(ctx context.Context, articleID uint, userId uint, usertype uint) error {
	if err := s.isPermission(ctx, articleID, userId, usertype); err != nil {
		return err
	}
	if err := s.articleRepo.DeleteArticleById(ctx, articleID); err != nil {
		return err
	}
	return s.relationSvc.DeleteRelationsByArticleID(ctx, articleID)
}

func (s *articleService) isPermission(ctx context.Context, articleID uint, userId uint, usertype uint) error {
	switch usertype {
	case model.UserTypeAdmin:
		return nil
	case model.UserTypeNormal:
		article, err := s.articleRepo.GetArticleByID(ctx, articleID)
		if err != nil {
			return err
		}
		if article.AuthorID != userId {
			return errors.New("无该文章权限")
		}
		return nil
	default:
		return errors.New("权限不足")
	}
}
